package db.ibatis.oth;

import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.plugin.Plugin;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Map;
import java.util.Properties;


import db.ibatis.Page;

/**
 * Create on 04/30/2017
 *
 * @author Asin Liu
 */

@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})

public class PageInterceptor implements Interceptor {

    private String dbType;

    public Object intercept(Invocation invocation) throws Throwable {

        StatementHandler handler = (StatementHandler) invocation.getTarget();


        // OGNL expression . See the field of RoutingStatementHandler which named delegate and with the type of PreparedStatementHandler.
        MappedStatement statement = null; // (MappedStatement)metaObject.getValue("delegate.mappedStatement");

        // Get the id in mapper.xml
        String id = statement.getId();
        if (id.matches(".+ByPage$")) {
            BoundSql boundSql = handler.getBoundSql();
            // Get the jdbc sql
            String jdbcSql = boundSql.getSql();

            String countSql = "select count(1) from (" + jdbcSql + ") a";
            Connection connection = (Connection) invocation.getArgs()[0];
            PreparedStatement countStatement = connection.prepareStatement(countSql);

            ParameterHandler parameterHandler = null; //(ParameterHandler) metaObject.getValue("delegate.parameterHandler");
            parameterHandler.setParameters(countStatement);
            ResultSet rs = countStatement.executeQuery();

            // Get the parameter from mapper parameter
            //Map<String,Object> parameter = (Map<String,Object>) boundSql.getParameterObject();
            Map<?, ?> parameter = (Map<?, ?>) boundSql.getParameterObject();
            Page page = (Page) parameter.get("page");

            if (rs.next()) {
                long cnt = rs.getLong(1);
                if (cnt < 1)
                    return null;
                else
                    page.setTotalNumber((int) cnt);
            }
            // Set the pager sql for mysql
            String pagerSql = jdbcSql + " limit " + page.getDbIndex() + "," + page.getPageSize();

            System.out.println(pagerSql);
            //metaObject.setValue("delegate.boundSql.sql",pagerSql);

        }
        return invocation.proceed();
    }

    public Object plugin(Object target) {
        if (target instanceof StatementHandler) {
            return Plugin.wrap(target, this);
        }
        return target;
    }

    public void setProperties(Properties properties) {
        System.out.println("setting the properties of the ibatis plugin...");
        this.dbType = properties.getProperty("dbType");
    }
}
